package com.boboPlanet.filter;

import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.boboPlanet.comm.component.JwtProperties;
import com.boboPlanet.comm.enums.GatewayConstance;
import com.boboPlanet.dao.GatewayMapper;
import com.boboPlanet.entity.vo.AllowPathVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Description: TODO 路由控制（黑/白名单）过滤器,不通过JWT校验，不认证
 * @Author: mis_wu
 * @Date: 2023/6/20
 * @Company planet
 * 注：requestPath是经过yaml配置截取后的 StripPrefix，yaml中自带的过滤器顺序为-1所以会先执行
 * 请求头标记 allow  true:放行   false:校验
 **/
@Component
@Slf4j
public class RouteControlFilter implements GlobalFilter, Ordered {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private GatewayMapper gatewayMapper;

    /**
     * 允许通过拦截路径
     */
    private static List<String> ALLOW_PATH_LIST = new LinkedList<>();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String requestPath = request.getURI().getPath();
        log.info("request into gateway routeFilter, current path is: {}", requestPath);
        //黑白名单配置
        this.initRoutePassFilter();

        //白名单通过路径
        if (!ALLOW_PATH_LIST.isEmpty() && ALLOW_PATH_LIST.contains(requestPath)){

            ServerHttpRequest build = request.mutate().headers(httpHeaders ->
                    httpHeaders.set(GatewayConstance.ALLOW_FILTER, String.valueOf(true))
            ).build();

            exchange.mutate().request(build);

        }
        return chain.filter(exchange);
    }

    /**
     * 初始化网关放行路径
     * @PostConstruct
     * todo:不能初始化加载。如果修改数据库或者redis服务出错，则获取的数据还是旧数据
     */
    @DS("dict")
    public void initRoutePassFilter(){
        String pathStr = stringRedisTemplate.opsForValue().get(GatewayConstance.ALLOW_PASS_PATH_KEY);
        if (StringUtils.isNotBlank(pathStr)){
            log.info("planet gateway routeFilter init routes, get redis pass pathStr ...");
            ALLOW_PATH_LIST = JSON.parseArray(pathStr, String.class);
        }else {
            List<AllowPathVo> allAllowPath = gatewayMapper.getAllAllowPath(null, 0, 2000);
            log.info("planet gateway routeFilter init routes, get db pass pathStr ...");
            ALLOW_PATH_LIST = allAllowPath.stream().filter(Objects::nonNull).map(AllowPathVo::getAllowPath).collect(Collectors.toList());
            if (!ALLOW_PATH_LIST.isEmpty()){
                stringRedisTemplate.opsForValue().set(GatewayConstance.ALLOW_PASS_PATH_KEY, JSON.toJSONString(ALLOW_PATH_LIST),1, TimeUnit.DAYS);
            }
        }
    }

    @Override
    public int getOrder() {
        return 1;
    }
}
